package com.xuyiwei.xblog.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xuyiwei.xblog.constant.XConstant;
import com.xuyiwei.xblog.entity.SysUser;
import com.xuyiwei.xblog.exception.BaseException;
import com.xuyiwei.xblog.mapper.SysUserMapper;
import com.xuyiwei.xblog.security.XUser;
import com.xuyiwei.xblog.security.util.JwtUtil;
import com.xuyiwei.xblog.service.ISysMenuService;
import com.xuyiwei.xblog.service.ISysUserRoleService;
import com.xuyiwei.xblog.service.ISysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author xuyiwei
 * @since 2019-07-30
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    private Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysUserRoleService userRoleService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public SysUser findByUserName(String username) {
        return baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
                .select(SysUser::getId, SysUser::getUsername, SysUser::getPassword)
                .eq(SysUser::getUsername, username));
    }

    @Override
    public Set<String> findPermsByUserId(Integer userId) {
        return menuService.findPermsByUserId(userId).stream().
                filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
    }

    @Override
    public Set<String> findRoleIdByUserId(Integer userId) {
        return userRoleService
                .selectUserRoleListByUserId(userId)
                .stream()
                .map(sysUserRole -> "ROLE_" + sysUserRole.getId())
                .collect(Collectors.toSet());
    }

    @Override
    public String login(String username, String password, String captcha, String uuid,HttpServletRequest request) {
        // 验证验证码
        // 从redis中获取之前保存的验证码跟前台传来的验证码进行匹配
        Object kaptcha = redisTemplate.opsForValue().get(XConstant.X_IMAGE_SESSION_KEY+"_"+uuid);
        if (kaptcha == null) {
            throw new BaseException("验证码已失效", 402);
        }
        if (!captcha.toLowerCase().equals(kaptcha)) {
            throw new BaseException("验证码错误", 402);
        }
        //用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername()去验证用户名和密码，
            // 如果正确，则存储该用户名密码到security 的 context中
            authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new BaseException("用户名或密码错误", 402);
            } else if (e instanceof DisabledException) {
                throw new BaseException("账户被禁用", 402);
            } else if (e instanceof AccountExpiredException) {
                throw new BaseException("账户过期无法验证", 402);
            } else {
                throw new BaseException("账户被锁定,无法登录", 402);
            }
        }
        //存储认证信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //生成token
        XUser userDetail = (XUser) authentication.getPrincipal();
        String token = JwtUtil.generateToken(userDetail);
        log.info("jwt生成的token:"+token);
        XUser user = JwtUtil.getUserFromToken(token);
        log.info("jwtToken得到的用户:"+user);
        return token;
    }
}
